﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Aphysoft.Vate.Graphics
{
    public static class CameraManager
    {
        #region Constants

        public const string DefaultCameraName = "DefaultCamera";

        #endregion

        #region Properties
        /// <summary>
        /// Other cameras.
        /// </summary>
        private static Dictionary<string, Camera> cameras;
        /// <summary>
        /// Gets other cameras.
        /// </summary>
        public static Dictionary<string, Camera> Cameras
        {
            get { return cameras; }
        }
        /// <summary>
        /// Default camera.
        /// </summary>
        private static Camera defaultCamera = null;
        /// <summary>
        /// Gets default camera.
        /// </summary>
        public static Camera DefaultCamera
        {
            get {  return defaultCamera; }
        }
        /// <summary>
        /// Camera Debugger.
        /// </summary>
        private static CameraDebugger debugger = null;
        /// <summary>
        /// True if CameraManager has been inited; otherwise, false.
        /// </summary>
        private static bool inited = false;
        #endregion

        #region Initiator
        /// <summary>
        /// Initializes CameraManager.
        /// </summary>
        public static void Init()
        {
            if (inited)
                throw new Exception("CameraManager has been initialized.");
            else
                inited = true;

            cameras = new Dictionary<string, Camera>();

            // create an entry as default camera
            defaultCamera = new Camera(DefaultCameraName);

#if DEBUG
            // register camera debugger.
            debugger = new CameraDebugger();

            Debug.Write("CameraManager Initialized.");
#endif
        }

        #endregion

        #region Methods
        /// <summary>
        /// Add a camera to camera manager.
        /// </summary>
        /// <param name="name">The name of camera</param>
        public static Camera Add(string name)
        {
            return Add(name, Vector3.Zero, Vector3.Forward, Vector3.Up);
        }
        /// <summary>
        /// Add a camera to camera manager.
        /// </summary>
        /// <param name="name">The name of camera</param>
        /// <param name="position">Camera position</param>
        /// <param name="target">Camera target</param>
        /// <param name="up">Camera up</param>    
        public static Camera Add(string name, Vector3 position, Vector3 target, Vector3 up)
        {
            Camera existingCamera = Find(name);

            if (existingCamera == null)
            {
                Camera newCamera = new Camera(name);

                newCamera.Position = position;
                newCamera.CameraTarget = target;

                cameras.Add(name, newCamera);

                Debug.Write(StringHelper.Create("New Camera \"", name, "\" added."));

                return newCamera;
            }
            else
            {
                // update camera properties
                existingCamera.Position = position;
                existingCamera.CameraTarget = target;

                return existingCamera;
            }
        }

        internal static Camera Add(string name, Camera camera)
        {
            Camera existingCamera = Find(name);

            if (existingCamera == null)
            {
                cameras.Add(name, camera);

                Debug.Write(StringHelper.Create("New Camera \"", name, "\" added."));

                return camera;
            }
            else
            {
                return camera;
            }
        }


        /// <summary>
        /// Remove camera specified by its name. Returns true if succeeded.
        /// </summary>
        /// <param name="name">The name of camera</param>
        public static bool Remove(string name)
        {
            if (cameras.ContainsKey(name))
            {
                cameras.Remove(name);
                return true;
            }
            else
                return false;
        }
        /// <summary>
        /// Gets a reference to camera specified by name.
        /// </summary>
        /// <param name="name">The name of camera.</param>
        public static Camera Find(string name)
        {
            if (name.Equals(DefaultCameraName))
                return DefaultCamera;
            else if (cameras.ContainsKey(name))
                return cameras[name];
            else
                return null;
        }
        #endregion
    }
}
